﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;
using CakeAnimation;

namespace CharacterAnimationEditor
{
    public class TimelineGui
    {
        Texture2D m_TimeLineTex;
        Texture2D m_KeyFrameTex;
        Texture2D m_TimeTickTex;


        private float m_Scale, m_Offset;
        private float m_Width = 500.0f;


        public TimelineGui(Context context)
        {
            m_Offset = 0.0f;
            m_Scale = 1.0f;

            m_KeyFrameTex = context.Content.Load<Texture2D>("KeyFrame");
            m_TimeLineTex = context.Content.Load<Texture2D>("TimeLine");
            m_TimeTickTex = context.Content.Load<Texture2D>("TimeTick");
        }

        private float GetTop(Context context)
        {
            return context.GD.Viewport.Height - 75;
        }


        public void Update(Context context)
        {
            TestKeyframeSwitch(context, Keys.D1, 0);
            TestKeyframeSwitch(context, Keys.D2, 1);
            TestKeyframeSwitch(context, Keys.D3, 2);
            TestKeyframeSwitch(context, Keys.D4, 3);
            TestKeyframeSwitch(context, Keys.D5, 4);
            TestKeyframeSwitch(context, Keys.D6, 5);
            TestKeyframeSwitch(context, Keys.D7, 6);

            if (context.MousePos.Y < GetTop(context))
            {
                return;
            }

            KeyFrame hovered = GetHovered(context);
            if (context.CurrMouseState.LeftButton == ButtonState.Pressed)
            {
                if (context.PrevMouseState.LeftButton == ButtonState.Released)
                {
                    if (hovered != null)
                    {
                        context.SetCurrentKeyFrame(hovered);
                    }
                    else if (context.CurrKeyState.IsKeyDown(Keys.LeftControl))
                    {
                        KeyFrameController controller = new KeyFrameController();

                        KeyFrame kf = new KeyFrame(context.AnimationContext, ScreenToTime(context), context.Animation.GetLastKeyframe().Pose);
                        context.Animation.GetPoseAt(kf.Time, kf.Pose);

                        int index = context.Animation.GetKeyFrameAt(ScreenToTime(context));

                        context.Animation.m_Keyframes.Insert(index, kf);
                        context.SetCurrentKeyFrame(kf);
                    }
                }
                else if (context.CurrentKeyFrame != context.Animation.m_Keyframes[0])
                {
                    float prevTime = ScreenToTime( context.PrevMouseState.X);
                    float currTime = ScreenToTime( context.MousePos.X);
                    float xdiff = context.MousePos.X - context.PrevMouseState.X;
                    context.CurrentKeyFrame.Time += currTime - prevTime;
                    context.Animation.m_Keyframes.Sort(delegate(KeyFrame k1, KeyFrame k2) { return k1.Time.CompareTo(k2.Time); });
                }
            }

            if (context.PrevMouseState.RightButton == ButtonState.Released && context.CurrMouseState.RightButton == ButtonState.Pressed)
            {
                if (hovered != null && context.Animation.m_Keyframes.Count > 1)
                {
                    context.Animation.m_Keyframes.Remove(hovered);
                    int frame = context.Animation.GetKeyFrameBeforeTime(hovered.Time);
                    context.SetCurrentKeyFrame(context.Animation.m_Keyframes[frame]);
                }
            }

            if (context.CurrMouseState.MiddleButton == ButtonState.Pressed)
            {
                float prevTime = ScreenToTime(context.PrevMouseState.X);
                float currTime = ScreenToTime(context.MousePos.X);
                float xdiff = context.MousePos.X - context.PrevMouseState.X;
                m_Offset += xdiff;
                m_Offset = Math.Max(0.0f, m_Offset);
            }

            if (context.MouseScroll != 0)
            {
                m_Scale *= 1.0f - (context.MouseScroll * 0.1f);
            }

        }

        private void TestKeyframeSwitch(Context context, Keys key, int i)
        {
            if (i >= context.Animation.m_Keyframes.Count)
            {
                return;
            }

            if (context.CurrKeyState.IsKeyDown(key))
                context.SetCurrentKeyFrame(context.Animation.m_Keyframes[i]);
        }


        private KeyFrame GetHovered(Context context)
        {
            if (context.MousePos.Y < GetTop(context))
                return null;

            float mx = context.MousePos.X;
            foreach (var item in context.Animation.m_Keyframes)
            {
                if (Math.Abs(TimeToScreen(item.Time) - mx) < 30)
                {
                    return item;
                }
            }

            return null;
        }


        private float ScreenToTime(float mx)
        {
            return (m_Scale * (mx - 50 + m_Offset) / m_Width);
        }

        private float ScreenToTime(Context context)
        {
            return ScreenToTime( context.MousePos.X);
        }

        public float TimeToScreen(float time)
        {
            return 50 - m_Offset + time * m_Width / (m_Scale);
        }

        public void Draw(Context context)
        {
            context.SpriteBatch.Draw(
                m_TimeLineTex,
                new Vector2(50, GetTop(context)),
                context.MousePos.Y > GetTop(context) ? Color.White : Color.Gray
                );

            KeyFrame hovered = GetHovered(context);


            for (int i = 0; i < context.Animation.m_Keyframes.Count; ++i)
            {
                KeyFrame kf = context.Animation.m_Keyframes[i];
                float xpos = TimeToScreen(kf.Time);
                context.SpriteBatch.Draw(
                    m_KeyFrameTex,
                    new Vector2(xpos - m_KeyFrameTex.Width / 2, kf == context.CurrentKeyFrame ? GetTop(context) + 10 : GetTop(context) + 30),
                    kf == hovered || kf == context.CurrentKeyFrame ? Color.White : Color.DimGray
                    );

                context.SpriteBatch.DrawString(
                    context.Font,
                    "t=" + String.Format("{0:0.##}", kf.Time),
                    new Vector2(xpos, GetTop(context) + 70),
                    Color.White);
            }


            context.SpriteBatch.DrawString(
                context.Font,
                "t=" + ScreenToTime(context).ToString(),
                context.MousePos,
                Color.Black);

            if (context.CurrKeyState.IsKeyDown(Keys.LeftControl) && hovered == null && context.MousePos.Y > GetTop(context))
            {
                context.SpriteBatch.Draw(
                    m_KeyFrameTex,
                    new Vector2(context.MousePos.X - m_KeyFrameTex.Width / 2, GetTop(context) + 30),
                    Color.Gray
                    );

            }

            int maxT = (int)Math.Ceiling(ScreenToTime(50 + m_Width));
            for (int i = 0; i < maxT; i++)
            {
                context.SpriteBatch.Draw(
                    m_TimeTickTex,
                    new Vector2(TimeToScreen(i), GetTop(context)),
                    Color.White
                    );

            }
        }
    }
}
